home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 3 / Info_Mac_1994-01.iso / Development / General / GCC 1.37.1r15 / Machines / out-tahoe.c < prev    next >
Text File  |  1990-03-14  |  13KB  |  551 lines

  1. /* Subroutines for insn-output.c for Tahoe.
  2.    Copyright (C) 1989 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU CC.
  5.  
  6. GNU CC is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU CC is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU CC; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20.  
  21. /*
  22.  * File: output-tahoe.c
  23.  *
  24.  * This port made at the University of Buffalo by Devon Bowen,
  25.  * Dale Wiles and Kevin Zachmann.
  26.  *
  27.  * Mail bugs reports or fixes to:    gcc@cs.buffalo.edu
  28.  */
  29.  
  30.  
  31. /* most of the print_operand_address function was taken from the vax    */
  32. /* since the modes are basically the same. I had to add a special case,    */
  33. /* though, for symbol references with offsets.                */
  34.  
  35. #include <stdio.h>
  36.  
  37. print_operand_address (file, addr)
  38.      FILE *file;
  39.      register rtx addr;
  40. {
  41.   register rtx reg1, reg2, breg, ireg;
  42.   rtx offset;
  43.   static char *reg_name[] = REGISTER_NAMES;
  44.  
  45.  retry:
  46.   switch (GET_CODE (addr))
  47.     {
  48.     case MEM:
  49.       fprintf (file, "*");
  50.       addr = XEXP (addr, 0);
  51.       goto retry;
  52.  
  53.     case REG:
  54.       fprintf (file, "(%s)", reg_name [REGNO (addr)]);
  55.       break;
  56.  
  57.     case PRE_DEC:
  58.       fprintf (file, "-(%s)", reg_name [REGNO (XEXP (addr, 0))]);
  59.       break;
  60.  
  61.     case POST_INC:
  62.       fprintf (file, "(%s)+", reg_name [REGNO (XEXP (addr, 0))]);
  63.       break;
  64.  
  65.     case PLUS:
  66.       reg1 = 0;    reg2 = 0;
  67.       ireg = 0;    breg = 0;
  68.       offset = 0;
  69.  
  70.       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
  71.       && GET_CODE (XEXP (addr, 1)) == CONST_INT)
  72.     output_addr_const (file, addr);
  73.  
  74.       if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
  75.       && GET_CODE (XEXP (addr, 0)) == CONST_INT)
  76.     output_addr_const (file, addr);
  77.  
  78.       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
  79.       || GET_CODE (XEXP (addr, 0)) == MEM)
  80.     {
  81.       offset = XEXP (addr, 0);
  82.       addr = XEXP (addr, 1);
  83.     }
  84.       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
  85.            || GET_CODE (XEXP (addr, 1)) == MEM)
  86.     {
  87.       offset = XEXP (addr, 1);
  88.       addr = XEXP (addr, 0);
  89.     }
  90.       if (GET_CODE (addr) != PLUS)
  91.     ;
  92.       else if (GET_CODE (XEXP (addr, 0)) == MULT)
  93.     {
  94.       reg1 = XEXP (addr, 0);
  95.       addr = XEXP (addr, 1);
  96.     }
  97.       else if (GET_CODE (XEXP (addr, 1)) == MULT)
  98.     {
  99.       reg1 = XEXP (addr, 1);
  100.       addr = XEXP (addr, 0);
  101.     }
  102.       else if (GET_CODE (XEXP (addr, 0)) == REG)
  103.     {
  104.       reg1 = XEXP (addr, 0);
  105.       addr = XEXP (addr, 1);
  106.     }
  107.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  108.     {
  109.       reg1 = XEXP (addr, 1);
  110.       addr = XEXP (addr, 0);
  111.     }
  112.       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
  113.     {
  114.       if (reg1 == 0)
  115.         reg1 = addr;
  116.       else
  117.         reg2 = addr;
  118.       addr = 0;
  119.     }
  120.       if (offset != 0)
  121.     {
  122.       if (addr != 0) abort ();
  123.       addr = offset;
  124.     }
  125.       if (reg1 != 0 && GET_CODE (reg1) == MULT)
  126.     {
  127.       breg = reg2;
  128.       ireg = reg1;
  129.     }
  130.       else if (reg2 != 0 && GET_CODE (reg2) == MULT)
  131.     {
  132.       breg = reg1;
  133.       ireg = reg2;
  134.     }
  135.       else if (reg2 != 0 || GET_CODE (addr) == MEM)
  136.     {
  137.       breg = reg2;
  138.       ireg = reg1;
  139.     }
  140.       else
  141.     {
  142.       breg = reg1;
  143.       ireg = reg2;
  144.     }
  145.       if (addr != 0)
  146.     output_address (offset);
  147.       if (breg != 0)
  148.     {
  149.       if (GET_CODE (breg) != REG)
  150.         abort ();
  151.       fprintf (file, "(%s)", reg_name[REGNO (breg)]);
  152.     }
  153.       if (ireg != 0)
  154.     {
  155.       if (GET_CODE (ireg) == MULT)
  156.         ireg = XEXP (ireg, 0);
  157.       if (GET_CODE (ireg) != REG)
  158.         abort ();
  159.       fprintf (file, "[%s]", reg_name[REGNO (ireg)]);
  160.     }
  161.       break;
  162.  
  163.     default:
  164.       output_addr_const (file, addr);
  165.     }
  166. }
  167.  
  168.  
  169. /* Do a quick check and find out what the best way to do the */
  170. /* mini-move is. Could be a push or a move.....             */
  171.  
  172. static char *
  173. singlemove_string (operands)
  174.      rtx *operands;
  175. {
  176.   if (GET_CODE (operands[0]) == MEM
  177.       && GET_CODE (XEXP (operands[0],0)) == PRE_DEC)
  178.     return "pushl %1";
  179.   return "movl %1,%0";
  180. }
  181.  
  182.  
  183. /* given the rtx for an address, return true if the given */
  184. /* register number is used in the address somewhere.      */
  185.  
  186. int
  187. regisused (addr,regnum)
  188.      rtx addr;
  189.      int regnum;
  190. {
  191.   if (GET_CODE (addr) == REG)
  192.     {
  193.       if (REGNO (addr) == regnum)
  194.     return (1);
  195.       else
  196.     return (0);
  197.     }
  198.  
  199.   if (GET_CODE (addr) == MEM)
  200.     return regisused (XEXP (addr,0),regnum);
  201.  
  202.   if (GET_CODE (addr) == MULT || GET_CODE (addr) == PLUS)
  203.     return (regisused (XEXP (addr,0),regnum)
  204.         || regisused (XEXP (addr,1),regnum));
  205.  
  206.   return 0;
  207. }
  208.  
  209.  
  210. /* Given some rtx, traverse it and return the register used in a */
  211. /* index. If no index is found, return 0.             */
  212.  
  213. rtx
  214. index_reg (addr)
  215.      rtx addr;
  216. {
  217.   rtx temp;
  218.  
  219.   if (GET_CODE (addr) == MEM)
  220.     return index_reg (XEXP (addr,0));
  221.  
  222.   if (GET_CODE (addr) == MULT)
  223.     {
  224.       if (GET_CODE (XEXP (addr,0)) == REG)
  225.     return XEXP (addr,0);
  226.       else
  227.     return XEXP (addr,1);
  228.     }
  229.  
  230.   if (GET_CODE (addr) == PLUS)
  231.     {
  232.       if (temp = index_reg (XEXP (addr,0)))
  233.     return temp;
  234.       else
  235.     return index_reg (XEXP (addr,1));
  236.     }
  237.  
  238.   return 0;
  239. }
  240.  
  241.  
  242. /* simulate the move double by generating two movl's. You have */
  243. /* to be careful about mixing modes here. A future improvement */
  244. /* would be to allow immediate doubles.                   */
  245.  
  246. char *
  247. output_move_double (operands)
  248.      rtx *operands;
  249. {
  250.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, INDOP, CNSTOP, RNDOP } optype0, optype1;
  251.   rtx latehalf[2];
  252.   rtx shftreg0 = 0, shftreg1 = 0;
  253.   rtx temp0 = 0, temp1 = 0;
  254.   rtx addreg0 = 0, addreg1 = 0;
  255.   int dohighfirst = 0;
  256.  
  257.   /* First classify both operands. */
  258.  
  259.   if (REG_P (operands[0]))
  260.     optype0 = REGOP;
  261.   else if ((GET_CODE (operands[0])==MEM) && (shftreg0=index_reg (operands[0])))
  262.     optype0 = INDOP;
  263.   else if (offsettable_memref_p (operands[0]))
  264.     optype0 = OFFSOP;
  265.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  266.     {
  267.       optype0 = PUSHOP;
  268.       dohighfirst++;
  269.     }
  270.   else if (GET_CODE (operands[0]) == MEM)
  271.     optype0 = MEMOP;
  272.   else
  273.     optype0 = RNDOP;
  274.  
  275.   if (REG_P (operands[1]))
  276.     optype1 = REGOP;
  277.   else if ((GET_CODE (operands[1])==MEM) && (shftreg1=index_reg (operands[1])))
  278.     optype1 = INDOP;
  279.   else if (offsettable_memref_p (operands[1]))
  280.     optype1 = OFFSOP;
  281.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  282.     optype1 = POPOP; 
  283.   else if (GET_CODE (operands[1]) == MEM)
  284.     optype1 = MEMOP;
  285.   else if (GET_CODE (operands[1]) == CONST_DOUBLE || CONSTANT_P (operands[1]))
  286.     optype1 = CNSTOP;
  287.   else
  288.     optype1 = RNDOP;
  289.  
  290.   /* set up for the high byte move for operand zero */
  291.  
  292.   switch (optype0)
  293.     {
  294.  
  295.       /* if it's a register, just use the next highest in the */
  296.       /* high address move.                    */
  297.  
  298.     case REGOP:
  299.       latehalf[0] = gen_rtx (REG,SImode,REGNO (operands[0])+1);
  300.       break;
  301.  
  302.       /* for an offsettable address, use the gcc function to  */
  303.       /* modify the operand to get an offset of 4 higher for  */
  304.       /* the second move.                    */
  305.  
  306.     case OFFSOP:
  307.       latehalf[0] = adj_offsettable_operand (operands[0], 4);
  308.       break;
  309.  
  310.       /* if the operand is MEMOP type, it must be a pointer    */
  311.       /* to a pointer. So just remember to increase the mem    */
  312.       /* location and use the same operand.            */
  313.  
  314.     case MEMOP:
  315.       latehalf[0] = operands[0];
  316.       addreg0 = XEXP (operands[0],0);
  317.       break;
  318.  
  319.       /* if we're dealing with a push instruction, just leave */
  320.       /* the operand alone since it auto-increments.        */
  321.  
  322.     case PUSHOP:
  323.       latehalf[0] = operands[0];
  324.       break;
  325.  
  326.       /* YUCK! Indexed addressing!! If the address is considered   */
  327.       /* offsettable, go use the offset in the high part. Otherwise */
  328.       /* find what exactly is being added to the mutiplication. If */
  329.       /* it's a mem reference, increment that with the high part   */
  330.       /* being unchanged to cause the shift. If it's a reg, do the */
  331.       /* same. If you can't identify it, abort. Remember that the  */
  332.       /* shift register was already set during identification.     */
  333.  
  334.     case INDOP:
  335.       if (offsettable_memref_p (operands[0]))
  336.     {
  337.       latehalf[0] = adj_offsettable_operand (operands[0],4);
  338.       break;
  339.     }
  340.  
  341.       latehalf[0] = operands[0];
  342.  
  343.       temp0 = XEXP (XEXP (operands[0],0),0);
  344.       if (GET_CODE (temp0) == MULT)
  345.     {
  346.       temp1 = temp0;
  347.       temp0 = XEXP (XEXP (operands[0],0),1);
  348.     }
  349.       else
  350.     {
  351.       temp1 = XEXP (XEXP (operands[0],0),1);
  352.       if (GET_CODE (temp1) != MULT)
  353.         abort ();
  354.     }
  355.  
  356.       if (GET_CODE (temp0) == MEM)
  357.     addreg0 = temp0;
  358.       else if (GET_CODE (temp0) == REG)
  359.     addreg0 = temp0;
  360.       else
  361.     abort ();
  362.  
  363.       break;
  364.  
  365.       /* if we don't know the operand type, print a friendly  */
  366.       /* little error message...   8-)            */
  367.  
  368.     case RNDOP:
  369.       default:
  370.       abort ();
  371.     }
  372.  
  373.   /* do the same setup for operand one */
  374.  
  375.   switch (optype1)
  376.     {
  377.  
  378.     case REGOP:
  379.       latehalf[1] = gen_rtx (REG,SImode,REGNO (operands[1])+1);
  380.       break;
  381.  
  382.     case OFFSOP:
  383.       latehalf[1] = adj_offsettable_operand (operands[1], 4);
  384.       break;
  385.  
  386.     case MEMOP:
  387.       latehalf[1] = operands[1];
  388.       addreg1 = XEXP (operands[1],0);
  389.       break;
  390.  
  391.     case POPOP:
  392.       latehalf[1] = operands[1];
  393.       break;
  394.  
  395.     case INDOP:
  396.       if (offsettable_memref_p (operands[1]))
  397.     {
  398.       latehalf[1] = adj_offsettable_operand (operands[1],4);
  399.       break;
  400.     }
  401.  
  402.       latehalf[1] = operands[1];
  403.  
  404.       temp0 = XEXP (XEXP (operands[1],0),0);
  405.       if (GET_CODE (temp0) == MULT)
  406.     {
  407.       temp1 = temp0;
  408.       temp0 = XEXP (XEXP (operands[1],0),1);
  409.     }
  410.       else
  411.     {
  412.       temp1 = XEXP (XEXP (operands[1],0),1);
  413.       if (GET_CODE (temp1) != MULT)
  414.         abort ();
  415.     }
  416.  
  417.       if (GET_CODE (temp0) == MEM)
  418.     addreg1 = temp0;
  419.       else if (GET_CODE (temp0) == REG)
  420.     addreg1 = temp0;
  421.       else
  422.     abort ();
  423.  
  424.       break;
  425.  
  426.     case CNSTOP:
  427.       /* Since this machine is big-endian,
  428.      the late half must be the low-order word for an integer,
  429.      or the latter word for a float.  */
  430.       if (GET_CODE (operands[1]) == CONST_DOUBLE)
  431.     {
  432.       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
  433.         {
  434.           latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
  435.                      CONST_DOUBLE_HIGH (operands[1]));
  436.           operands[1] = gen_rtx (CONST_INT, VOIDmode,
  437.                      CONST_DOUBLE_LOW (operands[1]));
  438.         }
  439.       else
  440.         {
  441.           latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
  442.                      CONST_DOUBLE_LOW (operands[1]));
  443.           operands[1] = gen_rtx (CONST_INT, VOIDmode,
  444.                      CONST_DOUBLE_HIGH (operands[1]));
  445.         }
  446.     }
  447.       else
  448.     {
  449.       latehalf[1] = operands[1];
  450.       operands[1] = const0_rtx;
  451.     }
  452.       break;
  453.  
  454.     case RNDOP:
  455.     default:
  456.       abort ();
  457.     }
  458.  
  459.  
  460.   /* double the register used for shifting in both of the operands */
  461.   /* but make sure the same register isn't doubled twice!       */
  462.  
  463.   if (shftreg0 && shftreg1 && rtx_equal_p (shftreg0, shftreg1))
  464.     output_asm_insn ("addl2 %0,%0", &shftreg0);
  465.   else
  466.     {
  467.       if (shftreg0)
  468.     output_asm_insn ("addl2 %0,%0", &shftreg0);
  469.       if (shftreg1)
  470.     output_asm_insn ("addl2 %0,%0", &shftreg1);
  471.     }
  472.  
  473.   /* if the destination is a register and that register is needed in  */
  474.   /* the source addressing mode, swap the order of the moves since we */
  475.   /* don't want this destroyed til last. If both regs are used, not   */
  476.   /* much we can do, so abort. If these becomes a problem, maybe we   */
  477.   /* can do it on the stack?                          */
  478.  
  479.   if (GET_CODE (operands[0])==REG && regisused (operands[1],REGNO (operands[0])))
  480.     if (regisused (latehalf[1],REGNO (latehalf[0])))
  481.       8;
  482.     else
  483.       dohighfirst++;
  484.  
  485.   /* if we're pushing, do the high address part first. */
  486.  
  487.   if (dohighfirst)
  488.     {
  489.  
  490.       if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1)))
  491.     output_asm_insn ("addl2 $4,%0", &addreg0);
  492.       else
  493.     {
  494.       if (addreg0)
  495.         output_asm_insn ("addl2 $4,%0", &addreg0);
  496.       if (addreg1)
  497.         output_asm_insn ("addl2 $4,%0", &addreg1);
  498.     }
  499.  
  500.       output_asm_insn (singlemove_string (latehalf), latehalf);
  501.  
  502.       if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1)))
  503.     output_asm_insn ("subl2 $4,%0", &addreg0);
  504.       else
  505.     {
  506.       if (addreg0)
  507.         output_asm_insn ("subl2 $4,%0", &addreg0);
  508.       if (addreg1)
  509.         output_asm_insn ("subl2 $4,%0", &addreg1);
  510.     }
  511.  
  512.       return singlemove_string (operands);
  513.     }
  514.  
  515.   output_asm_insn (singlemove_string (operands), operands);
  516.  
  517.   if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1)))
  518.     output_asm_insn ("addl2 $4,%0", &addreg0);
  519.   else
  520.     {
  521.       if (addreg0)
  522.     output_asm_insn ("addl2 $4,%0", &addreg0);
  523.       if (addreg1)
  524.     output_asm_insn ("addl2 $4,%0", &addreg1);
  525.     }
  526.  
  527.   output_asm_insn (singlemove_string (latehalf), latehalf);
  528.  
  529.   if (addreg0 && addreg1 && (rtx_equal_p (addreg0,addreg1)))
  530.     output_asm_insn ("subl2 $4,%0", &addreg0);
  531.   else
  532.     {
  533.       if (addreg0)
  534.     output_asm_insn ("subl2 $4,%0", &addreg0);
  535.       if (addreg1)
  536.     output_asm_insn ("subl2 $4,%0", &addreg1);
  537.     }
  538.  
  539.   if (shftreg0 && shftreg1 && (rtx_equal_p (shftreg0,shftreg1)))
  540.     output_asm_insn ("shar $1,%0,%0", &shftreg0);
  541.   else
  542.     {
  543.       if (shftreg0)
  544.     output_asm_insn ("shar $1,%0,%0", &shftreg0);
  545.       if (shftreg1)
  546.     output_asm_insn ("shar $1,%0,%0", &shftreg1);
  547.     }
  548.  
  549.   return "";
  550. }
  551.